var HandlerNode = {
	isDocumentNode: function(node){
		return (typeof node.nodeType != 'undefined' && node.nodeType == 9);
	},
	isElementNode: function(node){
		return (typeof node.nodeType != 'undefined') && node.nodeType == 1;
	},
	isTextNode: function(node){
		return (typeof node.nodeType != 'undefined') && node.nodeType == 3;
	},
	isAttributeNode: function(node){
		return (typeof node.nodeType != 'undefined') && node.nodeType == 2;
	},
	isOtherNode: function(node){
		var type = node.nodeType;
		if(type == 'undefined') return true;
		else{
			return type != 9 && type != 1 && type != 3 && type != 2;
		}
	},
	isEmptyTextNode: function(node){
//		if(node.normalize){
//			node.normalize();
//		}
		var value = node.nodeValue;
		if(value == null) return true;
		else{
			value = trim(value);
			return (value.length == 0);
		}
	}
};

var HTMLHandler = {
	readText: function(text){
		alert(text);
	},
	
	// Các phương thức phân loại thẻ HTML
	heading: ['H1', 'H2', 'H3', 'H4', 'H5', 'H6'],
	formating: ['HR','BR','B','EM','I','SMALL','STRONG','SUB','SUP','INS','DEL','CODE','KBD','SAMP','VAR','PRE','ABBR','ADDRESS','BLOCKQUOTE','Q','CITE','DFN'],
	isHeading: function(node){
		return this.heading.indexOf(node.tagName) != -1;
	},
	isParagraph: function(node){
		return node.tagName == 'P';
	},
	isFormatting: function(node){
		return this.formating.indexOf(node.tagName) != -1;
	},
	isLink: function(node){
		return node.tagName == 'A';
	},
	isImage: function(node){
		return node.tagName == 'IMG';
	},
	isListLI: function(node){
		return node.tagName == 'LI';
	},
	isINPUT: function(node){
		return node.tagName == 'INPUT';
	},
	
	
	isTable: function(node){
		return node.tagName == 'TABLE';
	},
	isList: function(node){
		return node.tagName == 'UL' || node.tagName == 'OL';
	},
	isBlock: function(node){
		return node.tagName == 'DIV' || node.tagName == 'SPAN';
	},
	isForm: function(node){
		return node.tagName == 'FORM';
	},
	
	// Các phương thức xử lí các loại thẻ HTML
	
	// Xử lí heading node {h1,h2,h3,h4,h5,h6}
	// Xác định cấp của đề mục, sau đó đọc text trong để mục
	handleHeading: function(node){
		var level = node.tagName.charAt(node.tagName.length-1);
		var text = "Đề mục ";
		if(!isNaN(parseInt(level, 10))){
			text += "cấp "+level;
		}
		text += " ";
		this.readText(text + node.innerHTML);
	},
	
	
	// Xử lí node paragraph {p}
	// Thuật toán : chuẩn hóa node p, loại bỏ các node con format như br,b,i,..
	// Sau đó đọc toàn bộ văn bản lên
	handleParagraph: function(node){
		this.readText(node.textContent);
	},
	
	
	// Xử lí node Link {a} co thuoc tinh href va textNode con cua no
	handleLink: function(node){
		console.log("handle link");
		$(node).focus();
		$(node).keydown(function(event){
			console.log("link keydown");
			if(event.which == 13){
				console.log(" enter link");
				window.location.href = event.currentTarget.href;
			}
		});
		var href = node.href;
		this.readText("Liên kết "+ node.textContent +", Địa chỉ : "+ href);
	},
	
	
	// Xử lí node Image
	// Thuật toán : kiểm tra xem ảnh có được load hay không thông qua thuộc tính height và width
	handleImage: function(node){
		var text = '';
		if(node.height == 0 || node.width == 0){
			return;
		}
		text += 'Bức ảnh có chủ đề :' + node.alt;
		this.readText(text);	
	},
	
	// Xử lí Table
	// Có 2 trường hợp : 
	// TH1. Bảng dữ liệu cụ thể => cần thuật toán tìm caption của bảng
	// TH2. Bảng layout cho trang web => bỏ qua (Hiếm gặp vì ngày nay thiết kế layout bằng DIV và CSS
	handleTable: function(node){
		this.readtext('Bảng dữ liệu');
	},
	
	// Xử lí node LI
	handleListLI: function(node){
		
	},
	
	
	
	// Xử lí các loại control INPUT
	handleINPUT: function(node){
		$(node).focus();
		if(node.tagName == "INPUT"){
			var type = node.type;
			if(type == "text"){
				console.log("input text field");
				this.readText("Ô nhập liệu");
				node.value="";
			}else if(type == "button"){
				this.readText("Button");
				$(node).keydown(function(event){
					if(event.which == 13){
						console.log("button click");
						$(event.currentTarget).click();
					}
				});
			}else if(type == "checkbox"){
				var checked = node.checked;
				if(checked){
					this.readText("Ô checkbox đã được check");
				}else {
					this.readText("Ô checkbox chưa được check");
				}
				$(node).keydown(function(event){
					if(event.which == 13){
						console.log(" checkbox change");
						var checked = event.currentTarget.checked;
						event.currentTarget.checked = !checked;
					}
				});
				
			}else if(type == "password"){
				console.log("password input");
				this.readText("Ô nhập mật khẩu");
			}else if(type == "radio"){
				var checked = node.checked;
				if(checked){
					this.readText("Ô radio đã được chọn");
				}else {
					this.readText("Ô radio chưa được chọn");
				}
				$(node).keydown(function(event){
					if(event.which == 13){
						console.log('change radio ');
						var checked = event.currentTarget.checked;
						event.currentTarget.checked = !checked;
					}
				});
			}else if(type == "reset"){
				this.readText("Button Reset toàn bộ form");
				$(node).keydown(function(event){
					if(event.which == 13){
						console.log("reset form");
						event.currentTarget.form.reset();
						$(event.currentTarget.form[0]).focus();
					}
				});
			}else if(type == "submit"){
				this.readText("Button Submit toàn bộ form");
				$(node).keydown(function(event){
					if(event.which == 13){
						console.log("Submit form");
						$(event.currentTarget.form).submit();
					}
				});
			}
		}else if(node.tagName == "SELECT"){
			this.readText("select");
		}else if(node.tagName == "TEXTAREA"){
			this.readText("textarea");
		}else{
			// Loại Control khác, hiện tại chưa xử lí
		}
	},
	
	
	// Xử lí ...
};


/**
 * Đối tượng duyệt web, lưu trữ node hiện tại đang duyệt
 * VoiceBrowser cho phép đi tiếp hoặc quay lại node trong cây DOM
 * theo thứ tự duyệt trước
 * @author Khanh
 */
var VoiceBrowser = {
	root : null,
	currentNode : this.root,
	previousNode : null,
	tabIndex : 0,
	getNextNode : function(){
		// Nếu node hiện tại có ít nhất một con thì node được duyệt kế tiếp
		// là node con đầu tiên
		if(this.currentNode.hasChildNodes()){
			this.currentNode = this.currentNode.firstChild;
		} // Ngược lại, nếu không có con
		else{
			// Nếu currentNode là root thì không có gì để duyệt
			if(this.currentNode === this.root){
				return null;
			}
			
			// currentNode sẽ có parent dưới hoặc ít nhất băng root
			if(this.currentNode.nextSibling != null){
				// Node anh em kế tiếp sẽ là node tiếp theo nếu currentNode không phải lastChil
				this.currentNode = this.currentNode.nextSibling;
			}
			else{
				var temp = this.currentNode.parentNode;
				while(temp !== this.root){
					if(temp.nextSibling != null){
						this.currentNode = temp.nextSibling;
						break;
					}else temp = temp.parentNode;
				}
			}	
		}
		
		// Kiểm tra xem node tiếp theo có cần duyệt không
		// Nếu không cần duyệt (EmptyTextNode hoặc ElementBlockNode) thì duyệt node tiếp theo
		if(HandlerNode.isTextNode(this.currentNode)){
			if(HandlerNode.isEmptyTextNode(this.currentNode)) 
				this.getNextNode();
		}else if(HandlerNode.isElementNode(this.currentNode)){
			
			if(HTMLHandler.isBlock(this.currentNode) ||
					HTMLHandler.isFormatting(this.currentNode) || 
					HTMLHandler.isForm(this.currentNode) ||
					HTMLHandler.isList(this.currentNode) )
				this.getNextNode();
			
		}
	},
	getPreviousNode : function(){
		if(this.currentNode === this.root){
			return;
		}
		// Kiểm tra xem có node em không
		if(this.currentNode.previousSibling ){
			// Đi sang node desendant của node em
			this.currentNode = this.currentNode.previousSibling;
			while(this.currentNode.hasChildNodes()){
				this.currentNode = this.currentNode.lastChild;
			}
		} // Không có em trước đó
		else{
			// Đây là firstChild, node duyệt trước nó là parentNod
			this.currentNode = this.currentNode.parentNode;	
		}
		
		// Kiểm tra xem node trước có cần duyệt không
		// Nếu không cần duyệt (EmptyTextNode hoặc ElementBlockNode) thì duyệt node trước nữa
		if(HandlerNode.isTextNode(this.currentNode)){
			if(HandlerNode.isEmptyTextNode(this.currentNode)) 
				this.getPreviousNode();
		}else if(HandlerNode.isElementNode(this.currentNode)){
			if(HTMLHandler.isBlock(this.currentNode) ||
					HTMLHandler.isFormatting(this.currentNode) || 
					HTMLHandler.isForm(this.currentNode) ||
					HTMLHandler.isList(this.currentNode) )
				this.getPreviousNode();
		}
	},
	
	
	// Duyệt đến node nào thì sẽ xử lí node đó
	handleNode : function(){
		// Focus vào node trước khi xử lí
		$(this.currentNode).focus();
		
//		alert("nodeName:"+this.currentNode.nodeName+
//			  "\nnodeType:"+ this.currentNode.nodeType+
//			  "\ntagName:"+this.currentNode.tagName+
//			  "\ninnerHTML:"+this.currentNode.innerHTML);
		
		// Them Border mau do de danh dau node dang duoc xu li
		$(this.previousNode).removeClass("handlering");
		$(this.currentNode).addClass("handlering");
		
		/** Xử lí một node. */
		if(HTMLHandler.isHeading(this.currentNode)){
			HTMLHandler.handleHeading(this.currentNode);
		}else if(HTMLHandler.isParagraph(this.currentNode)){
			HTMLHandler.handleParagraph(this.currentNode);
		}else if(HTMLHandler.isImage(this.currentNode)){
			HTMLHandler.handleImage(this.currentNode);
		}else if(HTMLHandler.isLink(this.currentNode)){
			HTMLHandler.handleLink(this.currentNode);
		}else if(HTMLHandler.isListLI(this.currentNode)){
			HTMLHandler.handleListLI(this.currentNode);
		}else if(HTMLHandler.isTable(this.currentNode)){
			HTMLHandler.handleTable(this.currentNode);
		}else if(HTMLHandler.isINPUT(this.currentNode)){
			HTMLHandler.handleINPUT(this.currentNode);
		}else{
			// do nothing
		}
		
	}
};



/** Chuẩn hóa đơn giản chuỗi str, loại bỏ khoảng trắng đầu và cuối str. */
function trim(str){
    var ltrimpatt = /^\s*/g;
    var rtrimpatt = /\s*$/g;
    str = str.replace(ltrimpatt,'');
    str = str.replace(rtrimpatt,'');
    return str;
}






function preorderTraversal(root) {
	var n = root;
	while (n) {
		// If node have already been visited
		if (n.v) {
			// Remove mark for visited nodes
			n.v = false;
			// Once we reach the root element again traversal
			// is done and we can break
			if (n == root)
				break;
			if (n.nextSibling)
				n = n.nextSibling;
			else
				n = n.parentNode;
		}
		// else this is the first visit to the node
		else {
			//
//			 Do something with node here...
			//
//			if(VoiceBrowser.isTextNode(n)){
//				value = n.nodeValue;
//				alert(value + '\nLength = ' + value.length);
//				$(n).css("border", "1px solid red");
//			}

			// If node has childnodes then we mark this node as
			// visited as we are sure to be back later
			if (n.firstChild) {
				n.v = true;
				n = n.firstChild;
			} else if (n.nextSibling)
				n = n.nextSibling;
			else
				n = n.parentNode;
		}
	}
}

